package com.tyk.bookstore.back.task.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.IdGenerator;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.common.dal.mapper.dto.BinDto;
import com.tyk.bookstore.back.task.model.entity.TaskDo;
import com.tyk.bookstore.back.task.model.enume.TaskState;
import com.tyk.bookstore.back.task.model.query.TaskAddQuery;
import com.tyk.bookstore.back.task.model.query.TaskPageQuery;
import com.tyk.bookstore.back.task.model.query.TaskUpdateQuery;
import com.tyk.bookstore.back.task.model.query.TaskUpdateStateQuery;
import com.tyk.bookstore.back.task.model.result.TaskResultEnum;
import com.tyk.bookstore.back.task.model.vo.TaskPageVo;
import com.tyk.bookstore.back.task.model.vo.TaskVo;
import com.tyk.bookstore.back.task.repository.TaskRepository;
import com.tyk.bookstore.back.task.schedule.ISchedulingConfigurer;
import com.tyk.bookstore.back.task.schedule.TaskEnum;
import com.tyk.bookstore.back.task.schedule.TaskHelper;
import com.tyk.bookstore.back.task.service.TaskService;
import com.tyk.bookstore.back.task.util.MapStructTask;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;


/**
 * @author tyk
 * @description 定时任务
 */
@Service
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskRepository, TaskDo> implements TaskService {

    private final TaskRepository taskRepository;
    private final ISchedulingConfigurer configurer;
    private final MapStructTask mapStructTask;

    private final TaskHelper taskHelper;


/**
 * 初始化定时任务
 */
@PostConstruct
private void init() {

    // 状态为开启的定时任务
    List<BinDto<String, String>> taskList = taskRepository.selectBinList1Eq(
            TaskDo::getName, TaskDo::getCron,
            TaskDo::getState, TaskState.OPEN,
            TaskDo.class
    );

    // 开启任务
    taskList.forEach(it -> {

        // 定时任务类型
        TaskEnum type = TaskEnum.of(it.getV1());
        AssertUtil.notNull(type, TaskResultEnum.TASK_NOT_SUPPORT);

        // 执行定时任务
        configurer.addTask(
                it.getV1(),
                taskHelper.getTask(type),
                it.getV2()
        );

    });
}

    @Override
    public TaskVo getById(Long id) {
        TaskDo task = taskRepository.selectById(id);
        AssertUtil.notNull(task, TaskResultEnum.TASK_NOT_FOUND);
        return mapStructTask.toTaskVo(task);
    }

    @Override
    public TaskPageVo getPage(TaskPageQuery query) {
        Page<TaskDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<TaskDo> w = buildPageQueryWrapper(query);
        taskRepository.selectPage(page, w);
        return mapStructTask.toTaskPageVo(page);
    }


    @Override
    public void add(TaskAddQuery query) {
        // 任务不重复
        AssertUtil.isFalse(
                taskRepository.exist1Eq(
                        TaskDo::getName, query.getName(), TaskDo.class
                ),
                TaskResultEnum.TASK_ALREADY_EXISTS
        );
        // 添加
        TaskDo task = mapStructTask.toTaskDo(query);
        task.setId(IdGenerator.id());
        taskRepository.insert(task);
    }

    @Override
    public void updateById(TaskUpdateQuery query) {
        // 任务存在
        AssertUtil.isTrue(
                taskRepository.exist1Eq(
                        TaskDo::getId, query.getId(), TaskDo.class
                ),
                TaskResultEnum.TASK_NOT_FOUND
        );
        // 任务不重复
        TaskDo task = mapStructTask.toTaskDo(query);
        AssertUtil.isFalse(
                taskRepository.exist1Eq1Ne(
                        TaskDo::getName, query.getName(),
                        TaskDo::getId, query.getId(),
                        TaskDo.class
                ),
                TaskResultEnum.TASK_ALREADY_EXISTS
        );
        taskRepository.updateById(task);
    }

    @Override
    public void deleteById(Long id) {
        AssertUtil.isTrue(
                taskRepository.exist1Eq(
                        TaskDo::getId, id, TaskDo.class
                ),
                TaskResultEnum.TASK_NOT_FOUND
        );
        taskRepository.deleteById(id);
    }

    @Override
    public void deleteBatchByIdSet(Set<Long> idSet) {
        AssertUtil.equal(
                taskRepository.count1In(
                        TaskDo::getId, idSet, TaskDo.class
                ),
                (long) idSet.size(),
                TaskResultEnum.TASK_NOT_FOUND
        );
        taskRepository.deleteBatchIds(idSet);
    }

    @Override
    public void updateState(TaskUpdateStateQuery query) {
        AssertUtil.isTrue(
                taskRepository.exist1Eq(
                        TaskDo::getId, query.getId(), TaskDo.class
                ),
                TaskResultEnum.TASK_NOT_FOUND
        );
        taskRepository.update1Set1Eq(
                TaskDo::getState, query.getState(),
                TaskDo::getId, query.getId(),
                TaskDo.class
        );

        // 名称、Cron表达式
        BinDto<String, String> task = taskRepository.selectBin1Eq(
                TaskDo::getName, TaskDo::getCron,
                TaskDo::getId, query.getId(),
                TaskDo.class
        );

        // 类型枚举
        TaskEnum type = TaskEnum.of(task.getV1());
        AssertUtil.notNull(type, TaskResultEnum.TASK_NOT_SUPPORT);

        // 开启/关闭
        switch (query.getState()) {
            case OPEN -> configurer.addTask(
                    task.getV1(),
                    taskHelper.getTask(type),
                    task.getV2()
            );
            case CLOSE -> configurer.removeTask(task.getV1());
        }

    }


    /**
     * 构建分页查询Wrapper
     */
    private LambdaQueryWrapper<TaskDo> buildPageQueryWrapper(TaskPageQuery query) {

        LambdaQueryWrapper<TaskDo> w = new LambdaQueryWrapper<>();

        w.like(ObjUtil.notBlank(query.getKeyword()), TaskDo::getDescription, query.getKeyword());

        w.like(ObjUtil.notBlank(query.getName()), TaskDo::getName, query.getName());

        w.like(ObjUtil.notBlank(query.getModule()), TaskDo::getModule, query.getModule());

        w.like(ObjUtil.notBlank(query.getMethod()), TaskDo::getMethod, query.getMethod());

        w.eq(query.getState() != null, TaskDo::getState, query.getState());

        w.ge(query.getCreateTimeFrom() != null, TaskDo::getCreateTime, query.getCreateTimeFrom());
        w.le(query.getCreateTimeTo() != null, TaskDo::getCreateTime, query.getCreateTimeTo());

        w.ge(query.getUpdateTimeFrom() != null, TaskDo::getUpdateTime, query.getUpdateTimeFrom());
        w.le(query.getUpdateTimeTo() != null, TaskDo::getUpdateTime, query.getUpdateTimeTo());

        w.orderBy(true, false, TaskDo::getCreateTime);

        return w;
    }


}

